package com.miyake.dsp.otdr.ui;

import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;

import com.miyake.dsp.otdr.Fiber;
import com.miyake.dsp.otdr.FiberManager;
import com.miyake.dsp.otdr.FiberNode;
import com.miyake.dsp.otdr.FiberNode.NodeType;
import com.miyake.dsp.otdr.NodeProperties;
import com.miyake.dsp.otdr.OtdrSetting;

public class FiberNodeUI {
	private FiberNode fiberNode;
	protected boolean root;
	protected int x;
	protected int y;
	
	protected JButton reference;
	
	static protected ImageIcon iconInactive = new ImageIcon("icon2.PNG");
	static protected ImageIcon iconNoneNode = new ImageIcon("NoneNode.PNG");
	static protected ImageIcon iconSplitter = new ImageIcon("splitter.PNG");
	static protected ImageIcon iconOTDR = new ImageIcon("otdr.PNG");
	static protected ImageIcon iconONU = new ImageIcon("onu.PNG");
	static protected ImageIcon iconOpen = new ImageIcon("open.PNG");
	static protected ImageIcon iconAPC = new ImageIcon("apc.PNG");
	
	public FiberNodeUI(NodeType type, NodeProperties fiberProperties,
			JButton ref) {
		fiberNode = new FiberNode(type, fiberProperties);
		fiberNode.setUserObject(this);
		reference = ref;
	}

	public static void main(String[] arg) {
		OtdrSettingUI e  = new OtdrSettingUI(new OtdrSetting(10e8, 1550, 10));
		JFrame f = new JFrame();
		f.setVisible(true);
		f.setSize(600,400);
		f.getContentPane().add(e);
	}

	public FiberNode getFiberNode() {
		return fiberNode;
	}

	public void setFiberNode(FiberNode fiberNode) {
		this.fiberNode = fiberNode;
	}
	
	public void remove(JButton ref) {
		for (FiberNode fn : getNodes()) {
			FiberNodeUI c = (FiberNodeUI)fn.getUserObject(); 
			if (c.getReference() == ref) {
				getNodes().remove(c.getFiberNode());
				getNodes().addAll(c.getFiberNode().getNodes());
				getNodes().addAll(c.getFiberNode().getNodes());
				return;
			}
			else {
				c.remove(ref);
			}	
		}
			
		if (getNodes().size() == 0 && (fiberNode.getNodeType() == NodeType.Connector || fiberNode.getNodeType() == NodeType.Splitter)) {
			this.setType(NodeType.Open);
		}
	}
	
	protected void initialize() {
		iconInactive = new ImageIcon("icon2.PNG");
		iconNoneNode = new ImageIcon("NoneNode.PNG");
		iconSplitter = new ImageIcon("splitter.PNG");
		iconOTDR = new ImageIcon("otdr.PNG");
		iconONU = new ImageIcon("onu.PNG");
		iconOpen = new ImageIcon("open.PNG");
		iconAPC = new ImageIcon("apc.PNG");
	}
	
	public boolean addNode(FiberNodeUI fiber) {
		if (this.getNodeType() == NodeType.OTDR && getNodes().size() > 0) {
			return false;
		}
		
		getNodes().add(fiber.getFiberNode());
		
		if (getNodes().size() > 1) {
			setType( NodeType.Splitter );
		}
		
		if (fiberNode.getNodeType() == NodeType.Open || fiberNode.getNodeType() == NodeType.ONU || fiberNode.getNodeType() == NodeType.APC) {
			setType(NodeType.Connector);
		}
		
		return true;
	}
	
	public void cancelSelection() {
		select(0,0,0,0,new Vector<JButton>());
	}
	
	public boolean isActive() {
		return reference.isBorderPainted();
	}
	
	public void select(int x1, int y1, int x2, int y2, Vector<JButton> vec) {
		
		if (reference.getX() > x1 && reference.getX() < x2 &&
				reference.getY() > y1 && reference.getY() < y2) {
			vec.add(reference);
			reference.setBorderPainted(true);
		}
		else {
			reference.setBorderPainted(false);
		}
		
		for (FiberNode node : getNodes()) {
			FiberNodeUI c = (FiberNodeUI)node.getUserObject();
			c.select(x1, y1, x2, y2, vec);		
		}
	}

	public void setSelected(JButton ref) {

		if (ref == reference) {
			reference.setBackground(Color.white);
			reference.setBorderPainted(true);
		}
		else {		
			reference.setBackground(Color.red);
			reference.setBorderPainted(false);
		}

		for (FiberNode node : getNodes()) {
			FiberNodeUI c = (FiberNodeUI)node.getUserObject();
			c.setSelected(ref);
		}
	}
	
	public void setIcon() {
		if (getNodeType() == NodeType.None) {
			reference.setIcon(iconNoneNode);
		}
		else if (getNodeType() == NodeType.ONU) {
			reference.setIcon(iconONU);
		}
		else if(getNodeType() == NodeType.Connector) {
			reference.setIcon(iconInactive);
		}
		else if(getNodeType() == NodeType.Splitter) {
			reference.setIcon(iconSplitter);
		}		
		else if(getNodeType() == NodeType.OTDR) {
			reference.setIcon(iconOTDR);
		}
		else if(getNodeType() == NodeType.Open) {
			reference.setIcon(iconOpen);
		}
		else if(getNodeType() == NodeType.APC) {
			reference.setIcon(iconAPC);
		}
	}
	
	public FiberNodeUI findFiber(JButton ref) {
		if (this.reference == ref) {
			return this;
		}
		else {
			FiberNodeUI ret;
			
			for (FiberNode node : getNodes()) {
				FiberNodeUI c = (FiberNodeUI)node.getUserObject();
				ret = c.findFiber(ref);
				if (ret != null) {
					return ret;
				}	
			}
		}
		
		return null;
	}

	public void drawLine(Graphics g) {
		setIcon();
		
		for (FiberNode node : getNodes()) {
			FiberNodeUI c = (FiberNodeUI)node.getUserObject();
			
			if (node.getNodeType() != NodeType.None) {
				int labelx = (reference.getX() + c.getX())/2 - 10;
				int labely = c.getY() + 4;
				g.drawString(String.valueOf(node.getProperties().getLength()) + "km", 
						labelx, labely);
			}
			
			if ((reference.getX() - c.getX()) == 0 || 
					(reference.getY() - c.getY()) == 0) {
				g.drawLine(
					reference.getX() + reference.getWidth()/2,
					reference.getY() + reference.getHeight()/2, 
					c.getX() + reference.getWidth()/2, 
					c.getY() + reference.getHeight()/2
					);
			}
			else {
				if ( (reference.getY() - c.getY()) < 0) {
					g.drawLine(
							reference.getX() + reference.getWidth()/2,
							reference.getY() + reference.getHeight()/2, 
							reference.getX() + reference.getWidth()/2, 
							c.getY() + reference.getHeight()/2
							);
					g.drawLine(
							reference.getX() + reference.getWidth()/2, 
							c.getY() + reference.getHeight()/2,
							c.getX() + reference.getWidth()/2, 
							c.getY() + reference.getHeight()/2);
				}
				else {
					g.drawLine(
							reference.getX() + reference.getWidth()/2,
							reference.getY() + reference.getHeight()/2, 
							reference.getX() + reference.getWidth()/2, 
							c.getY() + reference.getHeight()/2
							);
					g.drawLine(
							reference.getX() + reference.getWidth()/2, 
							c.getY() + reference.getHeight()/2,
							c.getX() + reference.getWidth()/2, 
							c.getY() + reference.getHeight()/2
							);
				}
			}
		
			c.drawLine(g);			

		}
	}

	/**
	 * @return the x
	 */
	public int getX() {
		return reference.getX();
	}

	/**
	 * @return the y
	 */
	public int getY() {
		return reference.getY();
	}

	/**
	 * @return the reference
	 */
	public JButton getReference() {
		return reference;
	}

	/**
	 * @param reference the reference to set
	 */
	public void setReference(JButton reference) {
		this.reference = reference;
	}

	/**
	 * @return the properties
	 */
	public NodeProperties getProperties() {
		return fiberNode.getProperties();
	}
	
	public void getSelectedProperties(Vector<NodeProperties> vec) {
		if (this.isActive()) {
			vec.add(fiberNode.getProperties());
		}
		
		for (FiberNode node : getNodes()) {
			FiberNodeUI c = (FiberNodeUI)node.getUserObject();
			c.getSelectedProperties(vec);
		}
	}
	public NodeProperties getSelectedProperties() {
		if (this.isActive()) {
			return fiberNode.getProperties();
		}
		else {
			for (FiberNode node : getNodes()) {
				FiberNodeUI c = (FiberNodeUI)node.getUserObject();
				NodeProperties p = c.getSelectedProperties();
				if (p != null) {
					return p;
				}
			}			
		}
		return null;
	}
	protected double[] addSecondReflect(double[] org) {
		double[] ret = new double[org.length * 2];
		double threshold = 0.001;
		double att = 1; // Attenuation from reflection point to near-end.
		double ref = Math.pow(10, fiberNode.getProperties().getReflectance()/10); // Reflection at OTDR
		for (int i = 0; i < org.length; i++) {
			ret[i] = org[i];
			if (org[i] > threshold) {
				//att = org[i-1];
				System.out.println("Hit @" + i);
				for (int j = 0; j < org.length; j++) {
					ret[i+j] += org[j] * org[i] * att * ref;
				}
			}
		}
		return ret;
	}
	
	/**
	 * @return the root
	 */
	public boolean isRoot() {
		return root;
	}

	/**
	 * @param root the root to set
	 */
	public void setRoot(boolean root) {
		this.root = root;
		fiberNode.getProperties().setLength(0);
		fiberNode.getProperties().setLength(0);
	}

	public boolean isSplitter() {
		if (getNodes().size() > 1)
			return true;
		
		return false;
	}

	public void update() {
		x = reference.getX();
		y = reference.getY();
		
		
		for (FiberNode node : getNodes()) {
			FiberNodeUI c = (FiberNodeUI)node.getUserObject();
			c.update();
		}
	}
	
	public void createButton() {
		reference = new JButton();
		reference.setBounds(x, y, 16, 16);
		reference.setIcon(iconInactive);
		for (FiberNode node : getNodes()) {
			FiberNodeUI c = (FiberNodeUI)node.getUserObject();
			c.createButton();
		}
	}
	
	public void getButtons(Vector<JButton> v) {
		v.add(reference);
		for (FiberNode node : getNodes()) {
			FiberNodeUI c = (FiberNodeUI)node.getUserObject();
			c.getButtons(v);
		}
	}

	/**
	 * @param type the type to set
	 */
	public void setType(NodeType type) {
		fiberNode.setNodeType(type);
		
		setDefaultProperties();
	}
	
	protected void setDefaultProperties() {
		if (getNodeType() == NodeType.APC) {
			fiberNode.getProperties().setReflectance(-90);
		}
		else if (getNodeType() == NodeType.Connector) {
			fiberNode.getProperties().setReflectance(-70);
		}
		else if (getNodeType() == NodeType.ONU) {
			fiberNode.getProperties().setReflectance(-60);
			
		}
		else if (getNodeType() == NodeType.Open) {
			fiberNode.getProperties().setReflectance(-14);
		}
	}
	
	private List<FiberNode> getNodes() {
		return fiberNode.getNodes();
	}
	
	public NodeType getNodeType() {
		return fiberNode.getNodeType();
	}

	public void updateFiber(FiberManager fiber) {
		fiberNode.updateFiber(fiber);
	}
}
